/*
 * File:    TimeUnit.java
 * Created: 06-Nov-2007
 * 
 * by Kenji Hollis <kenji@bitgatesoftware.com>
 * Released under the Creative Commons License version 2.5
 */

package com.bitgate.util.uom;

/**
 * This enumerated class is used to determine a unit of measure from a given expression.  You use the {@link TimeUnitParser}
 * to parse actual expressions of text, where this enumeration is used to simply return the time (in milliseconds) for
 * each given expression string.  This function gives you the ability to measure time using seconds, minutes, hours, days,
 * weeks, and years (both non-standard and lunar.)
 * <p></p>
 * <b>Note:</b> The {@link #YEAR} enumeration is less accurate than the {@link #LUNAR_YEAR} enumeration, however, the {@link #YEAR}
 * enumeration is the more "widely accepted" standard.  I have provided the ability to use both types of years to represent the
 * same values, depending on the scope of the application.
 * <p></p>
 * Because this is a unit of measure, there is no "accurate" way to measure a month, since each month has differing days, and
 * depending on the year, the year has more days than the previous - to indicate a leap year.  Therefore, the most generic way
 * to get a month in length is to either use a lookup table, or a ({@link #LUNAR_YEAR} / 4).
 * <p></p>
 * An easy way to quickly parse a string that contains a single expression is:<p></p>
 * <code>
 *     long milliseconds = TimeUnit.DEFAULT.parse("212d");
 * </code>
 * <p></p>
 * which will return a numeric value representing 212 days in milliseconds.
 * 
 * @author Kenji Hollis &lt;kenji@bitgatesoftware.com&gt;
 * @since 0.1
 */
public enum TimeUnit {
	
	/** Use this declaration when using the "parse" method, although "parse" can be used from any enumeration. */
	DEFAULT		(0L,							' '),
	
	/** One second in milliseconds - 1000ms, unit of measure is "S" */
	SECOND		(1000L,						 	'S'),
	
	/** One minute in milliseconds - 1000ms * 60 seconds, unit of measure is "M" */
	MINUTE		(1000L * 60,					'M'),
	
	/** One hour in milliseconds - 1000ms * 60 seconds * 60 minutes, unit of measure is "H" */ 
	HOUR		(1000L * 60 * 60,				'H'),
	
	/** One day in milliseconds - 1000ms * 60 seconds, * 60 minutes * 24 hours, unit of measure is "D" */
	DAY			(1000L * 60 * 60 * 24,			'D'),
	
	/** One week in milliseconds - 1000ms * 60 seconds * 60 minutes * 24 hours * 7 days, unit of measure is "W" */
	WEEK		(1000L * 60 * 60 * 24 * 7,		'W'),
	
	/** One year in milliseconds - 1000ms * 60 seconds * 60 minutes * 24 hours * 365 days, unit of measure is "Y", less accurate. */
	YEAR		(1000L * 60 * 60 * 24 * 365,	'Y'),
	
	/** One lunar year in milliseconds, 1000ms * 60 seconds * 60 minutes * 24 hours * 365.24 days, unit of measure is "L", more accurate. */
	LUNAR_YEAR	((long)(1000L * 60 * 60 * 24 * 365.24),	'L');
	
	private final long milliseconds;
	private final char unitIndicator;
	
	private TimeUnit(long milliseconds, char unitIndicator) {
		this.milliseconds = milliseconds;
		this.unitIndicator = unitIndicator;
	}
	
	/**
	 * Parses an expression in time format, and returns its value in milliseconds.
	 * 
	 * @param expression The <code>String</code> containing the expression to parse.
	 * @return <code>long</code> containing the time in milliseconds.
	 */
	public long parse(String expression) {
		char unitOfMeasure = expression.toUpperCase().charAt(expression.length() - 1);
		long unitOfTime = Long.parseLong(expression.substring(0, expression.length() - 1));
		
		for(TimeUnit tUnit : TimeUnit.values()) {
			if (tUnit.getUnitIndicator() == unitOfMeasure) {
				return (unitOfTime * tUnit.getMilliseconds());
			}
		}
		
		return 0L;
	}
	
	/**
	 * Gets the number of milliseconds represented by this enumeration.
	 * 
	 * @return <code>long</code> containing the number of milliseconds measured by this unit of time.
	 */
	public long getMilliseconds() {
		return this.milliseconds;
	}
	
	/**
	 * Indicates the unit of measure character associated with this time measurement.
	 * 
	 * @return <code>char</code> containing the notation to use.
	 */
	public char getUnitIndicator() {
		return this.unitIndicator;
	}
}